﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Factories;

namespace Pongster
{
    public class GamePlayScreen : BaseGameState
    {
        Texture2D backgroundImage;
        Texture2D middleImage;

        ParticleEngine particleEngine;

        private World world = new World(Vector2.Zero);

        private Texture2D ballTexture;
        private Texture2D ballTextureA;
        private Texture2D ballTextureB;
        private DrawablePhysicsCircle ball;
        public const float c_ballSpeed = 1.6f;
        public float ballSpeed;
        public float ballSpeedThreshold;

        private Texture2D paddleTexture;
        private Texture2D paddleTextureF;
        private DrawablePhysicsRectangle paddle1;
        private DrawablePhysicsRectangle paddle2;

        private Vector2 p1Pos = new Vector2(Settings.basescreenWidth / 2 - 160, Settings.basescreenHeight / 2 - 70);
        private Vector2 p2Pos = new Vector2(Settings.basescreenWidth / 2 + 20, Settings.basescreenHeight / 2 - 70);

        private int iPlayerOneScore = 0;
        private int iPlayerTwoScore = 0;
        private int lastHitter = 0;

        private Vector2 startPos = new Vector2(ConvertUnits.ToSimUnits(Settings.basescreenWidth / 2f),
                                         ConvertUnits.ToSimUnits(Settings.basescreenHeight / 2f));

        public GamePlayScreen(Game game, GameStateManager manager)
            : base(game, manager)
        {
            HasCursor = false;
        }


        public override void Initialize()
        {
            base.Initialize();

            GameRef.SoundManager.StopAll();
            GameRef.SoundManager.StopSong();
            GameRef.SoundManager.PlaySong("playtrack", true);

            ballSpeed = 1.6f;
            ballSpeedThreshold = 11f;

            ball = new DrawablePhysicsCircle(world, ballTexture, 12f, 1f);
            ball.Body.Restitution = 0.8f;
            ball.Body.Friction = 0.0f;
            ball.Body.FixedRotation = true;
            ball.Body.LinearDamping = 0.05f;
            ball.Body.AngularDamping = 0.2f;
            ball.Body.BodyId = 0;
            ball.Body.OnCollision += OnCollision;

            ResetBallPosition(startPos, new Vector2(-ballSpeed, 0.0f));
            
            paddle1 = new DrawablePhysicsRectangle(
                world,
                paddleTexture,
                new Vector2(52, 150),
                1
            );

            paddle1.Body.BodyType = BodyType.Dynamic;
            paddle1.Body.FixedRotation = true;
            paddle1.Body.Restitution = 0.1f;
            paddle1.Body.BodyId = 1;
            paddle1.Position = new Vector2(80, 500);
            paddle1.Body.LinearVelocity = new Vector2(0, 0);

            // Setup paddle 2
            paddle2 = new DrawablePhysicsRectangle(
                world,
                paddleTextureF,
                new Vector2(52, 150),
                1
            );

            paddle2.Body.BodyType = BodyType.Dynamic;
            paddle2.Body.FixedRotation = true;
            paddle2.Body.Restitution = 0.1f;
            paddle2.Body.BodyId = 2;
            paddle2.Position = new Vector2(1840, 500);
            paddle2.Body.LinearVelocity = new Vector2(0, 0);

                        
            var ceiling = BodyFactory.CreateRectangle(
                world,
                1800 * (1 / 60.0f),
                20 * (1 / 60.0f),
                1
            );

            ceiling.BodyType = BodyType.Static;
            ceiling.SleepingAllowed = true;
            ceiling.Position = new Vector2((Settings.basescreenWidth /2 ) * (1 / 60.0f), 20 * (1 / 60.0f));


            var floor = BodyFactory.CreateRectangle(
                world,
                1800 * (1 / 60.0f),
                20 * (1 / 60.0f),
                1
            );

            floor.BodyType = BodyType.Static;
            floor.SleepingAllowed = true;
            floor.Position = new Vector2((Settings.basescreenWidth / 2) * (1 / 60.0f), 1060 * (1 / 60.0f));
            
            lastHitter = 0;
            iPlayerOneScore = 0;
            iPlayerTwoScore = 0;
            
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            ContentManager Content = GameRef.Content;

            menuFont = Content.Load<SpriteFont>(@"Fonts\ScoreFont");

            backgroundImage = Content.Load<Texture2D>(@"Backgrounds\field");
            middleImage = Content.Load<Texture2D>(@"Backgrounds\middlewall");

            GameRef.SoundManager.LoadSong("playtrack", @"Audio\Music\playtrack");
            
            ballTextureA = Content.Load<Texture2D>(@"Graphics\ball");
            ballTextureB = Content.Load<Texture2D>(@"Graphics\ball3");
            ballTexture = Content.Load<Texture2D>(@"Graphics\ball2");
            paddleTexture = Content.Load<Texture2D>(@"Graphics\paddle");
            paddleTextureF = Content.Load<Texture2D>(@"Graphics\paddlef");

            GameRef.SoundManager.LoadSFX("point", @"Audio/SFX/point");
            GameRef.SoundManager.LoadSFX("bounce", @"Audio/SFX/bounce");

            List<Texture2D> textures = new List<Texture2D>();
            textures.Add(Content.Load<Texture2D>("particle"));
            particleEngine = new ParticleEngine(textures, new Vector2(0, 0));

        }

        public override void Update(GameTime gameTime)
        {
            if (InputHandler.KeyReleased(Keys.Escape) || InputHandler.KeyReleased(Keys.P))
            {
                Settings.mediaPlayerFree = false;
                MediaPlayer.Volume = 0.1f;
                StateManager.PushState(GameRef.PopUpScreen);
            }

            if(InputHandler.KeyReleased(Keys.Space))
                ballSpeed = 2f;

            world.Step((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f);

            SimulatePaddles();

            HandleInput();

            SimulateBall();
            
            particleEngine.Update();

            particleEngine.disabled = true;           

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            GameRef.SpriteBatch.Begin();

            GameRef.SpriteBatch.DrawString(menuFont, iPlayerOneScore.ToString("00"), p1Pos, Color.DimGray);
            //GameRef.SpriteBatch.DrawString(menuFont, ":", new Vector2(Settings.basescreenWidth / 2 - 37, Settings.basescreenHeight / 2 - 73), Color.DimGray);
            GameRef.SpriteBatch.DrawString(menuFont, iPlayerTwoScore.ToString("00"), p2Pos, Color.DimGray);

            GameRef.SpriteBatch.End();

            GameRef.SpriteBatch.Begin();

            GameRef.SpriteBatch.Draw(middleImage, new Rectangle(Settings.basescreenWidth / 2 - 20, 40, 40, 1000), Color.White);

            particleEngine.Draw(GameRef.SpriteBatch);

            GameRef.SpriteBatch.Draw(backgroundImage, GameRef.BaseRectangle, Color.White);
            ControlManager.Draw(GameRef.SpriteBatch);


            ball.Draw(GameRef.SpriteBatch);
            paddle1.Draw(GameRef.SpriteBatch);
            paddle2.Draw(GameRef.SpriteBatch);
            
            base.Draw(gameTime);

            GameRef.SpriteBatch.End();

        }

        public void SimulateBall()
        {
            if (Math.Abs(ball.Body.LinearVelocity.X) > 18f || Math.Abs(ball.Body.LinearVelocity.Y) > 21f)
                ball.texture = ballTextureA;
            else if (Math.Abs(ball.Body.LinearVelocity.X) > 14f || Math.Abs(ball.Body.LinearVelocity.Y) > 16f)
                ball.texture = ballTextureB;
            else
                ball.texture = ballTexture;


            if (Math.Abs(ball.Body.LinearVelocity.X) < ballSpeedThreshold && ball.Body.LinearVelocity.X < 0)
            {
                ball.Body.LinearVelocity += new Vector2(-ballSpeed, 0.0f);
            }

            if (Math.Abs(ball.Body.LinearVelocity.X) < ballSpeedThreshold && ball.Body.LinearVelocity.X > 0)
            {
                ball.Body.LinearVelocity += new Vector2(ballSpeed, 0.0f);
            }

            if (ball.Position.X <= 0)
            {
                iPlayerTwoScore += 1;
                ResetBallPosition(startPos, new Vector2(-c_ballSpeed, 0.0f));
                GameRef.SoundManager.PlayInstantSFX("point");
            }
            else if (ball.Position.X >= Settings.basescreenWidth)
            {
                iPlayerOneScore += 1;
                ResetBallPosition(startPos, new Vector2(c_ballSpeed, 0.0f));
                GameRef.SoundManager.PlayInstantSFX("point");
            }

            if (ball.Position.Y <= 0)
            {
                var nudge = lastHitter == 1 ? new Vector2(-c_ballSpeed, 0.0f) : new Vector2(c_ballSpeed, 0.0f);
                ResetBallPosition(startPos, nudge);
                GameRef.SoundManager.PlayInstantSFX("point");
            }
            else if (ball.Position.Y >= Settings.basescreenHeight)
            {
                var nudge = lastHitter == 1 ? new Vector2(-c_ballSpeed, 0.0f) : new Vector2(c_ballSpeed, 0.0f);
                ResetBallPosition(startPos, nudge);
                GameRef.SoundManager.PlayInstantSFX("point");

            }
        }

        public void SimulatePaddles()
        {
            MathHelper.Clamp(paddle1.Body.Position.X, 60, 80);
            MathHelper.Clamp(paddle2.Body.Position.X, 1840, 1860);

            if (paddle1.Position.X < 80)
                paddle1.Body.LinearVelocity += new Vector2(0.05f, 0);

            if (paddle2.Position.X > 1840)
                paddle2.Body.LinearVelocity -= new Vector2(0.05f, 0);

            if (paddle1.Position.Y <= 50 + 96 / 2)
            {
                paddle1.Body.LinearVelocity = Vector2.Zero;
                paddle1.Body.LinearVelocity += new Vector2(0, 1f);
            }
            else if (paddle1.Position.Y >= 1030 - 96 / 2)
            {
                paddle1.Body.LinearVelocity = Vector2.Zero;
                paddle1.Body.LinearVelocity -= new Vector2(0, 1f);
            }

            if (paddle2.Position.Y <= 50 + 96 / 2)
            {
                paddle2.Body.LinearVelocity = Vector2.Zero;
                paddle2.Body.LinearVelocity += new Vector2(0, 1f);
            }
            else if (paddle2.Position.Y >= 1030 - 96 / 2)
            {
                paddle2.Body.LinearVelocity = Vector2.Zero;
                paddle2.Body.LinearVelocity -= new Vector2(0, 1f);
            }

        }


        public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
        {
            if (f1.Body.BodyId == 0)
            {
                GameRef.SoundManager.PlayInstantSFX("bounce");

                particleEngine.disabled = false;
                particleEngine.EmitterLocation = ball.Position;

                lastHitter = f2.Body.BodyId;

                f1.Body.LinearVelocity += f2.Body.LinearVelocity * 1.2f;

                if (Math.Abs(f1.Body.LinearVelocity.X) < 10)
                {
                    f1.Body.LinearVelocity += f1.Body.LinearVelocity * 0.6f;
                }

                if (f2.Body.BodyId == 1 || f2.Body.BodyId == 2)
                {
                    if (ballSpeedThreshold < 24 && ballSpeed < 14)
                    {
                        ballSpeedThreshold += 0.4f;
                        ballSpeed += 0.4f;
                    }
                }

                return true;
            }
            return true;
        }

        public void HandleInput()
        {            
            if (InputHandler.KeyDown(Keys.W))
            {
                if (paddle1.Position.Y >= 50 + 96 / 2)
                {
                    if(paddle1.Body.LinearVelocity.Y > -20f)
                        paddle1.Body.LinearVelocity -= new Vector2(0, 2f);
                }
            }
            else if (InputHandler.KeyDown(Keys.S))
            {
                if (paddle1.Position.Y <= 1030 - 96 / 2)
                {
                    if (paddle1.Body.LinearVelocity.Y < 20f)
                        paddle1.Body.LinearVelocity += new Vector2(0, 2f);
                }
            }
            else
            {
                paddle1.Body.LinearVelocity = paddle1.Body.LinearVelocity -= 0.05f * paddle1.Body.LinearVelocity;
            }


            if (InputHandler.KeyDown(Keys.Up))
            {
                if (paddle2.Position.Y > 50 + 96 / 2)
                {
                    if (paddle2.Body.LinearVelocity.Y > -20f)
                    paddle2.Body.LinearVelocity -= new Vector2(0, 2f);
                }
            }
            else if (InputHandler.KeyDown(Keys.Down))
            {
                if (paddle2.Position.Y < 1030 - 96 / 2)
                {
                    if (paddle2.Body.LinearVelocity.Y < 20f)
                    paddle2.Body.LinearVelocity += new Vector2(0, 2f);
                }
            }
            else
            {
                paddle2.Body.LinearVelocity = paddle2.Body.LinearVelocity -= 0.05f * paddle2.Body.LinearVelocity;
            }
        }


        private void ResetBallPosition(Vector2 position, Vector2 nudge)
        {
            ballSpeed = 1.6f;
            ballSpeedThreshold = 11f;

            lastHitter = 0;
            ball.Body.ResetDynamics();
            ball.Body.Position = position;
            ball.Body.ApplyLinearImpulse(nudge, ball.Body.Position);
        }

    }
}
